package top.cardone.mapper.impl;

import com.google.common.collect.Maps;
import com.google.gson.Gson;
import lombok.Setter;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import top.cardone.context.ApplicationContextHolder;
import top.cardone.core.CodeException;
import top.cardone.mapper.BeanMapper;
import top.cardone.validator.Validator;

import java.util.Map;

/**
 * Created by Administrator on 2016/10/2.
 */
public class BeanMapperImpl implements BeanMapper {
	@Setter
	private String errorMessageSeparator = ";";

	@Override
	public Map<String, Object> getTable(Map<String, Object> map, String[] inputJsons, boolean cache) {
		if (ArrayUtils.isEmpty(inputJsons)) {
			return map;
		}

		Map<String, Object> newTable = Maps.newHashMap();

		if (ArrayUtils.getLength(inputJsons) == 1) {
			Map<String, Map<String, Object>> bigInputMap = top.cardone.context.util.MapUtils.newMap(inputJsons[0], cache);

			if (MapUtils.isEmpty(bigInputMap)) {
				return map;
			}

			for (Map.Entry<String, Map<String, Object>> bigInputEntry : bigInputMap.entrySet()) {
				Map<String, Object> newValue = top.cardone.context.util.MapUtils.newHashMap(map, bigInputEntry.getValue());

				newTable.put(bigInputEntry.getKey(), newValue);
			}

			return newTable;
		}

		Map<String, Map<String, Object>> bigInputMap = top.cardone.context.util.MapUtils.newMap(inputJsons[1], cache);

		if (MapUtils.isEmpty(bigInputMap)) {
			return map;
		}

		Map<String, Map<String, Map<String, Object>>> preValidateTable = top.cardone.context.util.MapUtils.newMap(inputJsons[0], cache);

		Map<String, Map<String, Map<String, Object>>> postValidateTable = null;

		if (ArrayUtils.getLength(inputJsons) > 2) {
			postValidateTable = top.cardone.context.util.MapUtils.newMap(inputJsons[2], cache);
		}

		for (Map.Entry<String, Map<String, Object>> bigInputEntry : bigInputMap.entrySet()) {
			if (MapUtils.isNotEmpty(preValidateTable)) {
				Map<String, String> errorMap = ApplicationContextHolder.getBean(Validator.class).validate(preValidateTable.get(bigInputEntry.getKey()), map);

				if (top.cardone.context.util.MapUtils.isNotEmpty(errorMap)) {
					throw new CodeException(org.apache.commons.lang3.StringUtils.join(errorMap.values(), errorMessageSeparator));
				}
			}

			Map<String, Object> newValue = top.cardone.context.util.MapUtils.newHashMap(map, bigInputEntry.getValue());

			if (MapUtils.isNotEmpty(postValidateTable)) {
				Map<String, String> errorMap = ApplicationContextHolder.getBean(Validator.class).validate(postValidateTable.get(bigInputEntry.getKey()), newValue);

				if (top.cardone.context.util.MapUtils.isNotEmpty(errorMap)) {
					throw new CodeException(org.apache.commons.lang3.StringUtils.join(errorMap.values(), errorMessageSeparator));
				}
			}

			newTable.put(bigInputEntry.getKey(), newValue);
		}

		return newTable;
	}

	@Override
	public <T> T getObject(Class<T> cls, String jsonString, Map<String, Object> map) {
		if (StringUtils.isBlank(jsonString) || !StringUtils.startsWithIgnoreCase(jsonString, "{")) {
			jsonString = "{}";
		} else {
			jsonString = StringUtils.trim(jsonString);
		}

		//输入参数为 map 时，优化获取 request 参数后，再合并
		if (Map.class.equals(cls)) {
			Map<String, Object> jsonMap = ApplicationContextHolder.getBean(Gson.class).fromJson(jsonString, Map.class);

			if (MapUtils.isNotEmpty(jsonMap)) {
				map.putAll(jsonMap);
			}

			return (T) map;
		}

		if (java.lang.String.class.equals(cls) || java.lang.Object.class.equals(cls)) {
			return (T) jsonString;
		}

		return ApplicationContextHolder.getBean(Gson.class).fromJson(jsonString, cls);
	}

	@Override
	public <T> T getObject(Class<T> cls, Map<String, Object> map) {
		if (java.util.Map.class.equals(cls) || java.lang.Object.class.equals(cls)) {
			return (T) map;
		}

		String jsonString = ApplicationContextHolder.getBean(Gson.class).toJson(map);

		if (java.lang.String.class.equals(cls) || java.lang.Object.class.equals(cls)) {
			return (T) jsonString;
		}

		return ApplicationContextHolder.getBean(Gson.class).fromJson(jsonString, cls);
	}

	@Override
	public <T> T getObject(Class<T> cls, Map<String, Object> map, String[] inputJsons, boolean cache) {
		if (ArrayUtils.getLength(inputJsons) == 1) {
			Map<String, Object> newMap = top.cardone.context.util.MapUtils.newHashMap(map, inputJsons[0], cache);

			return this.getObject(cls, newMap);
		}

		Map<String, String> errorMap = ApplicationContextHolder.getBean(Validator.class).validate(inputJsons[0], map, cache);

		if (top.cardone.context.util.MapUtils.isNotEmpty(errorMap)) {
			throw new CodeException(org.apache.commons.lang3.StringUtils.join(errorMap.values(), errorMessageSeparator));
		}

		Map<String, Object> newMap = top.cardone.context.util.MapUtils.newHashMap(map, inputJsons[1], cache);

		if (ArrayUtils.getLength(inputJsons) > 2) {
			errorMap = ApplicationContextHolder.getBean(Validator.class).validate(inputJsons[2], newMap, cache);

			if (top.cardone.context.util.MapUtils.isNotEmpty(errorMap)) {
				throw new CodeException(org.apache.commons.lang3.StringUtils.join(errorMap.values(), errorMessageSeparator));
			}
		}

		return this.getObject(cls, newMap);
	}

	@Override
	public <T> T getObject(Class<T> cls, Map<String, Object> map, Map<String, Object> mapperMap) {
		Map<String, Object> newMap = top.cardone.context.util.MapUtils.newHashMap(map, mapperMap);

		return this.getObject(cls, newMap);
	}
}
